package com.zhengbing.tj.interceptor;

import com.zhengbing.tj.common.UserContext;
import com.zhengbing.tj.entity.User;
import com.zhengbing.tj.service.UserService;
import com.zhengbing.tj.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * 系统认证拦截器
 * 验证token并注入用户上下文
 *
 * @author zhengbing
 * @date 2025-07-29
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    // 显式声明log变量以确保编译通过
    private static final Logger log = LoggerFactory.getLogger(AuthInterceptor.class);
    
    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private UserService userService;

    // 白名单路径，无需token验证
    private static final String[] WHITE_LIST = {
        "/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**", "/swagger-resources/configuration/**", // Swagger文档路径及资源
        "/webjars/**", // Knife4j静态资源
        "/api/users/login", "/api/users/register", // 登录、注册接口
        "/doc.html" // 文档页面
};

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        // 1. 检查是否是白名单路径
        String requestURI = request.getRequestURI();
        for (String whitePath : WHITE_LIST) {
            if (requestURI.startsWith(whitePath.replace("/**", ""))) {
                return true;
            }
        }

        // 2. 获取并验证token
        String token = request.getHeader("Authorization");
        log.info("接收到的Authorization头: {}", token);
        // 忽略Authorization头大小写差异，并支持Bearer后有空格或无空格两种格式
        if (token == null || (!token.trim().toLowerCase().startsWith("bearer ") && !token.trim().toLowerCase().equals("bearer"))) {
            response.setContentType("application/json;charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.write("{\"code\":401,\"message\":\"未授权访问，token不存在或格式错误\"}");
            out.flush();
            out.close();
            return false;
        }

        // 3. 解析token获取用户名
        // 处理Bearer后有空格或无空格两种格式
        if (token.trim().toLowerCase().startsWith("bearer ")) {
            token = token.trim().substring(7);
        } else {
            token = token.trim().substring(6);
        }
        String username = jwtUtils.getUsernameFromToken(token);
        if (username == null) {
            response.setContentType("application/json;charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.write("{\"code\":401,\"message\":\"token无效，无法获取用户名\"}");
            out.flush();
            out.close();
            return false;
        }

        // 4. 验证token有效性并获取用户信息
        if (!jwtUtils.validateToken(token, username)) {
            response.setContentType("application/json;charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.write("{\"code\":401,\"message\":\"token已过期或无效\"}");
            out.flush();
            out.close();
            return false;
        }

        // 5. 将用户信息存入上下文
        User user = userService.getUserByUsername(username);
        log.info("用户信息设置到上下文: {}", user.getName());
        UserContext.setUser(user);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 不需要实现
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求完成后清除上下文，避免内存泄漏
        log.info("清理用户上下文信息");
        UserContext.clear();
    }
}
